package com.core;


import com.adwszzy.ConfigConstants;
import com.adwszzy.ConfigurationMaps;
import com.adwszzy.ScreenMatcherThread;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import org.opencv.core.*;
import org.opencv.core.Point;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import java.awt.*;
import java.awt.event.InputEvent;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import static com.adwszzy.ScreenMatcher.*;


public class ScreenMatcher {
    public static void main(String[] args) {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        try {
            circleBorderDetection(new Robot());
        } catch (AWTException e) {
            throw new RuntimeException(e);
        }
//        Mat screenMat = Imgcodecs.imread("Z:\\Users\\adwszzy\\Desktop\\1231.png");
//        try {
//            ConfigurationMaps.load();
//            ScreenMatcherThread.mode=0;
////        // 1、匹配cost数
////        Mat template = Imgcodecs.imread(ConfigConstants.newPic);
////        //todo
////        matchAndPress(template, screenMat, robot, 0, 1);
//            //2、根据cost匹配属性
//            System.out.println("2、根据cost匹配属性");
//            int cNumber = matchAndContrastThread(screenMat, 0.3, Imgcodecs.imread(ConfigConstants.getC1Pic()), Imgcodecs.imread(ConfigConstants.getC3Pic()), Imgcodecs.imread(ConfigConstants.getC4Pic()));
//            System.out.println(cNumber);
//            JSONObject priorityInfo = null;
//            JSONArray attrArray ;
//            String path = null;
//            switch (cNumber) {
//                case 0:
//                    path = ConfigConstants.getC1Path();
//                    priorityInfo = ConfigurationMaps.priorityInfo.getJSONObject("1c");
//                    break;
//                case 1:
//                    path = ConfigConstants.getC3Path();
//                    priorityInfo = ConfigurationMaps.priorityInfo.getJSONObject("3c");
//                    break;
//                case 2:
//                    path = ConfigConstants.getC4Path();
//                    priorityInfo = ConfigurationMaps.priorityInfo.getJSONObject("4c");
//                    break;
//                default:
//                    System.out.println("cost数值识别失败");
//                    return;
//            }
//            //3、匹配套装
//            String suit=matchSuit(screenMat);
//            if (suit == null) {
//
//                System.out.println("套装识别失败");
//                return;
//            }else{
//                attrArray=priorityInfo.getJSONArray(suit);
//                if (matchAttr(screenMat, attrArray, path)) {//匹配属性 如果返回true就锁定
//                    System.out.println("123true321");
//                    //4、满足属性的点击锁定
////                    matchAndPressTheLock(screenMat,robot,0.5,0.1);
//                }
//            }
//        }finally {
//            screenMat.release();
//        }
    }

    /**
     * 基于 matchAndContrast 方法，使用线程缩短匹配时间
     * @param src
     * @param similarityMinimum
     * @param targets
     * @return
     */
    public static int matchAndContrastThread(Mat src,double similarityMinimum, Mat... targets) {
        // 创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
        try {
// 提交任务
            List<Future<Double>> futures = new ArrayList<>();
            Double[] doubles = new Double[targets.length];
            for (int i = 0; i < targets.length; i++) {
                Mat template = targets[i];
                int finalI = i;
                futures.add(executorService.submit(() -> {
                    Mat result = new Mat();
                    Imgproc.matchTemplate(src, template, result, Imgproc.TM_CCOEFF_NORMED);
//                    Imgproc.matchTemplate(src, template, result, Imgproc.TM_CCOEFF_NORMED);
                    Core.MinMaxLocResult mmr = Core.minMaxLoc(result);
                    return doubles[finalI] = mmr.maxVal;
                }));
            }

// 获取结果
            double maxScore = futures.stream()
                    .mapToDouble(future -> {
                        try {
                            double db = future.get();
                            System.out.println("--"+db);
                            return db < similarityMinimum ? 0.0 : db;
                        } catch (Exception e) {
                            throw new RuntimeException(e);
                        }
                    })
                    .max()
                    .orElse(0.0);
            System.out.println(maxScore);
            if (maxScore == 0.0) {
                return -1;
            } else {
                for (int i = 0; i < doubles.length; i++) {
                    Double aDouble = doubles[i];
                    if (aDouble.equals(maxScore)) return i;
                    break;
                }
            }
// 查找最佳匹配的模板
//        for (int i = 0; i < targets.length; i++) {
//            Mat template = targets[i];
//            Mat result = new Mat();
//            Imgproc.matchTemplate(src, template, result, Imgproc.TM_CCOEFF_NORMED);
//            Core.MinMaxLocResult mmr = Core.minMaxLoc(result);
//            if (mmr.maxVal == maxScore) {
//                bestMatchScore = mmr.maxVal;
//                bestMatchTemplate = template;
//                break;
//            }
//        }
            return -1;
        }finally {
            executorService.shutdown();
        }
    }
    public static void match(Mat target,Mat src,Robot robot) {
        Mat outputImage = new Mat(src.rows(), src.cols(), src.type());
        Imgproc.matchTemplate(src, target, outputImage, Imgproc.TM_CCOEFF_NORMED);

        // 4.获取匹配结果,查找最大匹配值
        Core.MinMaxLocResult result = Core.minMaxLoc(outputImage);
        Point matchLoc = result.maxLoc;
        double similarity = result.maxVal; //匹配度 低于0.8的不要
        int x = (int) matchLoc.x; //小图大大图中的x坐标
        int y = (int) matchLoc.y; //小图大大图中的y坐标
        System.out.println(x + "," + y + " similarity: " + similarity);
        robot.mouseMove(x, y);

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 执行鼠标左键点击
        robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
        robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);

        //将查找到的结果标上框框
//        Imgproc.rectangle(src,new Point(x,y),new Point(x+target.cols(),y+target.rows()),
//                new Scalar( 0, 0, 255),2);
//
//        //5.显示结果
//        HighGui.imshow("模板匹配", src);
//        HighGui.waitKey();

    }

    public static Mat getScreenShot(Robot robot) {
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        int screenWidth = screenSize.width;
        int screenHeight = screenSize.height;
        Rectangle screenRect = new Rectangle(screenWidth, screenHeight);
        BufferedImage screenImageTemp = robot.createScreenCapture(screenRect);

        BufferedImage screenImage = new BufferedImage(screenImageTemp.getWidth(), screenImageTemp.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
        screenImage.getGraphics().drawImage(screenImageTemp, 0, 0, null);
        // 将BufferedImage转换为Mat
//            Mat screenMat = ImageUtil.bufferedImageToMat(screenImage);
        return bufferedImageToMat(screenImage);
    }

    public static Mat bufferedImageToMat(BufferedImage bi) {
        Mat mat = new Mat(bi.getHeight(), bi.getWidth(), CvType.CV_8UC3);
        DataBuffer db=bi.getRaster().getDataBuffer();
        byte[] data = ((DataBufferByte)db ).getData();
        mat.put(0, 0, data);
        return mat;
    }
    // 以下为假设的非极大值抑制函数
    public static Mat applyNonMaxSuppression(Mat result, double threshold) {
        int windowSize = 3; // 例如，3x3窗口
        int padding = windowSize / 2;
        Mat resultCopy = new Mat();
        result.copyTo(resultCopy);

        for (int y = padding; y < result.rows() - padding; y++) {
            for (int x = padding; x < result.cols() - padding; x++) {
                double value = resultCopy.get(y, x)[0];
                boolean isMax = true;
                for (int ky = -padding; ky <= padding && isMax; ky++) {
                    for (int kx = -padding; kx <= padding && isMax; kx++) {
                        if (value < resultCopy.get(y + ky, x + kx)[0]) {
                            isMax = false;
                        }
                    }
                }
                if (!isMax || value < threshold) {
                    resultCopy.put(y, x, 0); // 抑制非极大值和低于阈值的值
                }
            }
        }
        return resultCopy;
    }
    public static void circleBorderDetection (Robot robot) {
//        Mat targetImage = Imgcodecs.imread("Z:/Users/adwszzy/Desktop/789.png");
//        Mat targetImage =getScreenShot(robot);
        Mat targetImage =Imgcodecs.imread("Z:\\Users\\adwszzy\\Desktop\\7890.png");;
        Mat template = Imgcodecs.imread("src/main/resource/picture/1080/icon/border.png");

        // 转换到HSV色彩空间
        Mat grayTarget = new Mat();
        Mat grayTemplate = new Mat();
        Imgproc.cvtColor(targetImage, grayTarget, Imgproc.COLOR_BGR2HSV_FULL);
        Imgproc.cvtColor(template, grayTemplate, Imgproc.COLOR_BGR2HSV_FULL);
        Scalar lowerBound = new Scalar(20, 39, 150); // 黄色
        Scalar upperBound = new Scalar(55, 100, 255);
        // 创建掩码
        Mat mask = new Mat();
        Core.inRange(grayTarget, lowerBound, upperBound, mask);
        // 应用掩码
        Mat res = new Mat();
        Core.bitwise_and(targetImage, targetImage, res, mask);


        // 边缘检测
        Mat edgesTarget = new Mat();
        Mat edgesTemplate = new Mat();
        Imgproc.Canny(res, edgesTarget, 50, 150);
        Imgproc.Canny(template, edgesTemplate, 50, 150);
        HighGui.imshow("模板匹配0", res);
        HighGui.imshow("模板匹配1", edgesTarget);

        // 模板匹配
        Mat result = new Mat();
        Imgproc.matchTemplate(edgesTarget, edgesTemplate, result, Imgproc.TM_CCORR_NORMED);

        // 设置阈值
        double threshold = 0.34;
        // 创建一个与result相同大小和类型的矩阵，并用threshold填充
        // 寻找匹配位置
        Mat resultAfterNMS = applyNonMaxSuppression(result, threshold);
        List<Point> locations = findLocations(resultAfterNMS, threshold);
//        List<Point> locations = findLocations(result, threshold);
        // 绘制匹配结果 // 显示结果
        drawMatches(targetImage,template, locations);
//
        targetImage.release();
        template.release();
        grayTarget.release();
        grayTemplate.release();
        edgesTarget.release();
        edgesTemplate.release();

    }
    public static void nonMaxSuppression(Mat edges) {
//        Mat angles = new Mat();
//        Imgproc.Sobel(edges, angles, CvType.CV_32F, 1, 0); // Calculate gradient in x-direction
//        Imgproc.Sobel(edges, angles, CvType.CV_32F, 0, 1); // Calculate gradient in y-direction
//
//        // Convert gradient directions to angles
//        Core.phase(angles, angles, false);
//
//        // Convert angles from [-pi, pi] to [0, 180]
//        angles.convertTo(angles, -1, 180.0 / Math.PI);
//        angles.convertTo(angles, CvType.CV_32F);
        Mat gradX = new Mat();
        Mat gradY = new Mat();

        // Calculate gradient magnitude and direction with Sobel operator
        Imgproc.Sobel(edges, gradX, CvType.CV_32F, 1, 0);
        Imgproc.Sobel(edges, gradY, CvType.CV_32F, 0, 1);

        Mat mag = new Mat();
        Mat angle = new Mat();
        Core.cartToPolar(gradX, gradY, mag, angle, true);
        // Apply non-maximum suppression
        for (int i = 1; i < edges.rows() - 1; i++) {
            for (int j = 1; j < edges.cols() - 1; j++) {
        if (edges.get(i, j)[0] != 0) { // If this is an edge pixel
            double angleVal = angle.get(i, j)[0];
            if ((0 <= angleVal && angleVal < 22.5) || (157.5 <= angleVal && angleVal <= 180)) {
                // Check horizontal neighbors
                if (edges.get(i, j)[0] <= edges.get(i, j - 1)[0] || edges.get(i, j)[0] <= edges.get(i, j + 1)[0]) {
                    edges.put(i, j, 0);
                }
            } else if (22.5 <= angleVal && angleVal < 67.5) {
                // Check diagonal neighbors
                if (edges.get(i, j)[0] <= edges.get(i - 1, j - 1)[0] || edges.get(i, j)[0] <= edges.get(i + 1, j + 1)[0]) {
                    edges.put(i, j, 0);
                }
            } else if (67.5 <= angleVal && angleVal < 112.5) {
                // Check vertical neighbors
                if (edges.get(i, j)[0] <= edges.get(i - 1, j)[0] || edges.get(i, j)[0] <= edges.get(i + 1, j)[0]) {
                    edges.put(i, j, 0);
                }
            } else if (112.5 <= angleVal && angleVal < 157.5) {
                // Check diagonal neighbors
                if (edges.get(i, j)[0] <= edges.get(i - 1, j + 1)[0] || edges.get(i, j)[0] <= edges.get(i + 1, j - 1)[0]) {
                    edges.put(i, j, 0);
                }
            }
        }
    }
}
    }
    public static void circleBorderDetection1 (Robot robot) {
//        Mat targetImage = Imgcodecs.imread("Z:/Users/adwszzy/Desktop/789.png");
//        Mat targetImage =getScreenShot(robot);
        Mat targetImage =Imgcodecs.imread("Z:\\Users\\adwszzy\\Desktop\\789.png");;
        Mat template = Imgcodecs.imread("src/main/resource/picture/icon/border1.png");

        // 转换到HSV色彩空间
        Mat grayTarget = new Mat();
//        Mat grayTemplate = new Mat();
        Imgproc.cvtColor(targetImage, grayTarget, Imgproc.COLOR_BGR2HSV_FULL);
//        Imgproc.cvtColor(template, grayTemplate, Imgproc.COLOR_BGR2HSV);
        // 转换为灰度图像
//        Mat grayTarget = new Mat();
//        Mat grayTemplate = new Mat();
//        Imgproc.cvtColor(targetImage, grayTarget, Imgproc.COLOR_BGR2GRAY);
//        Imgproc.cvtColor(template, grayTemplate, Imgproc.COLOR_BGR2GRAY);

        // 边缘检测

        // 定义绿色的范围
        Scalar lowerBound = new Scalar(45, 31, 0); // 黄色
        Scalar upperBound = new Scalar(255, 255, 255);
//        Scalar lowerBound = new Scalar(31, 27, 153); // 黄色
//        Scalar upperBound = new Scalar(41, 37, 255);
//        Scalar lowerBound = new Scalar(9, 81, 153); // 黄色
//        Scalar upperBound = new Scalar(19, 91, 255);
        HighGui.imshow("模板匹配2", grayTarget);
        // 创建掩码
        Mat mask = new Mat();
        Core.inRange(grayTarget, lowerBound, upperBound, mask);
        HighGui.imshow("模板匹配0", mask);
        // 应用掩码
        Mat res = new Mat();
        Core.bitwise_and(targetImage, targetImage, res, mask);

        // 边缘检测
        Mat edges = new Mat();
        Imgproc.Canny(res, edges, 50, 150);
        // 设置阈值
        double threshold = 0.25;
        HighGui.imshow("模板匹配1", edges);
        HighGui.waitKey();
        // 创建一个与result相同大小和类型的矩阵，并用threshold填充
        // 寻找匹配位置
//        List<Point> locations = findLocations(edges, threshold);
//        // 绘制匹配结果 // 显示结果
//        drawMatches(targetImage,template, locations);
//        for (Point point : locations) {
//            robot.mouseMove((int) (point.x + 10), (int) (point.y + 10));
//            robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
//            robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
//            try {
//                Thread.sleep(100);
//                //匹配声骸并锁定
//                matchAndlockTheSoundSkeleton(robot);
//                Thread.sleep(100);
//                //关闭该页面
//                Mat screenMat = getScreenShot(robot);
//                Mat template1 = Imgcodecs.imread(ConfigConstants.closePic);
//                matchAndPress(template1,screenMat, robot, 0, 0);
//                screenMat.release();
//                template1.release();
//                Thread.sleep(100);
//
//
//            } catch (InterruptedException e) {
//                throw new RuntimeException(e);
//            }
//        }
//        //随便点哪，返回！
//        Mat screenMat = getScreenShot(robot);
//        Mat template1 = Imgcodecs.imread(ConfigConstants.anywherePic);
//        matchAndPress(template1,screenMat, robot, 0, 0);

    }
    private static List<double[]> findMatchValues(Mat result, double threshold) {
        Mat thresholdMat = new Mat();
        Core.compare(result, new Scalar(threshold), thresholdMat, Core.CMP_GT);
        MatOfPoint loc = new MatOfPoint();
        Core.findNonZero(thresholdMat, loc);
        Point[] points = loc.toArray();

        List<double[]> matchValues = new ArrayList<>();
        for (Point p : points) {
            double similarity = result.get((int) p.y, (int) p.x)[0];
            matchValues.add(new double[]{p.x, p.y, similarity});
        }
        return matchValues;
    }
    private static List<Point> findLocations(Mat result, double threshold) {
//        nonMaxSuppression(result);
        Mat thresholdMat = new Mat();
        Core.compare(result,new Scalar(threshold), thresholdMat, Core.CMP_GT);
        MatOfPoint loc = new MatOfPoint();
        Core.findNonZero(thresholdMat, loc);
        Point[] points = loc.toArray();
        List<Point> locations = new ArrayList<>();
//        int i = 0;
        for (Point p : points) {
            double similarity = result.get((int) p.y, (int) p.x)[0];
            System.out.println("[debug]point： "+similarity);
            locations.add(p);
        }
        System.out.println("[debug]locations.size()： "+locations.size());
        return locations;
    }
}